package com.kungfuhacking.wristbandpro.mqtt;

import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;

import com.alibaba.fastjson.JSONObject;
import com.kungfuhacking.wristbandpro.base.bean.RequestBean;
import com.kungfuhacking.wristbandpro.database.DatabaseManager;
import com.kungfuhacking.wristbandpro.mqtt.bean.MessageBean;
import com.kungfuhacking.wristbandpro.mqtt.bean.MqttServiceBean;
import com.kungfuhacking.wristbandpro.net.BaseNoTObserver;
import com.kungfuhacking.wristbandpro.net.RetrofitHttpUtil;
import com.kungfuhacking.wristbandpro.utils.CommonUtils;
import com.kungfuhacking.wristbandpro.utils.Constant;
import com.kungfuhacking.wristbandpro.utils.File2Code;

import org.greenrobot.eventbus.EventBus;

import io.reactivex.disposables.Disposable;
import mqttresource.MqttClient;
import mqttresource.MqttConnectOptions;
import mqttresource.MqttException;
import mqttresource.MqttTopic;
import mqttresource.persist.MemoryPersistence;

/**
 * mqtt连接管理类
 * <p/>
 * Created by Aaron on 15/12/15.
 */
public class MqttManager {

    private MqttClient mqttClient;
    private Context context;

    private static MqttManager mqttManager = new MqttManager();
    private SharedPreferences sp;
    private MqttMessageCallBack callBack;

    private String TAG = getClass().getSimpleName();

    private MqttManager() {
    }

    public static MqttManager getInstance() {
        return mqttManager;
    }

    public MqttClient getMqttClient() {
        return mqttClient;
    }

    /**
     * 获取mqtt的ip和端口号
     */
    public void getMqttIp(final Context ctx) {

        this.context = ctx;

        if (sp == null)
            sp = ctx.getSharedPreferences(Constant.CONFIG, Context.MODE_PRIVATE);

        JSONObject j = new JSONObject();
        j.put("token", sp.getString(Constant.TOKEN, ""));

        RetrofitHttpUtil.getInstance().talkLogin(new BaseNoTObserver<MqttServiceBean>() {
            @Override
            public void onHandleSuccess(MqttServiceBean serviceBean) {

                Log.d(TAG, "    回调线程  : " + Thread.currentThread().getName() + ",是否是主线程:" + CommonUtils.isMainThread());
                SharedPreferences.Editor edit = sp.edit();
                //保存mqtt IP
                edit.putString(MqttConstant.MQTTIP, serviceBean.getIp());
                edit.putString(MqttConstant.MQTTPORT, serviceBean.getPort());
//                MqttConstant.topicMap = new HashMap<>();

                if (serviceBean.getTopicList() != null && serviceBean.getTopicList().size() > 0) {

                    MqttConstant.TOPICS = new String[serviceBean.getTopicList().size()];

                    for (int i = 0; i < serviceBean.getTopicList().size(); i++) {
                        MqttConstant.TOPICS[i] = serviceBean.getTopicList().get(i).topic;
//                        MqttConstant.topicMap.put(serviceBean.getTopicList().get(i).topic, serviceBean.getTopicList().get(i));

                        //查询topic表, 插入数据
                        DatabaseManager.getInstance().insertEmptyContent(ctx, serviceBean.getTopicList().get(i).topic, serviceBean.getTopicList().get(i).topicName
                                , serviceBean.getTopicList().get(i).topicImg, sp.getString(MqttConstant.USERID, ""));

                    }

                }

//                //删除topic表中的私聊和群聊信息
//                boolean aBoolean = sp.getBoolean(Constant.FIRST_ENTER_CLEAR, true);
//                if (aBoolean) {
//                    DatabaseManager.getInstance().clearChat(ctx);
//                    edit.putBoolean(Constant.FIRST_ENTER_CLEAR, false);
//                }

                //1推送消息， 0不推送消息
                edit.putBoolean(Constant.IS_NOTICE, serviceBean.getIsPush() == 1);

//                edit.putString(MqttConstant.TOPIC_MAP, JSON.toJSONString(MqttConstant.topicMap, true));//保存到sp中,防止内存中的被销毁
                edit.apply();

                //连接mqtt
                connectMqtt();
            }

            @Override
            public void onHandleError(String message) {

            }

            @Override
            public void onReLogin(String message) {
                sp.edit().putBoolean(MqttConstant.INTERVAL_CONNET_MQTT, false).apply();
            }

            @Override
            public void onSubscribe(Disposable d) {

            }
        }, new RequestBean().setData(j.toString()));

    }

    /**
     * 连接MQTT服务器
     * <p/>
     * 聊天的登录名称是用户的手机号,密码是token
     * clientid 是 保存的 用户的id即 userId
     * <p/>
     * //     * @param handlerMessage 连接成功后的需要处理的消息(比如发送消息的时候发现连接断开了,重新连接时需要发送的消息)
     */
    private void connectMqtt() {

        try {

            if (mqttClient != null && mqttClient.isConnected())
                return;

            mqttClient = new MqttClient(
                    "tcp://" + sp.getString(MqttConstant.MQTTIP, "") + ":" + sp.getString(MqttConstant.MQTTPORT, "")
                    , sp.getString(MqttConstant.USERID, ""), new MemoryPersistence());

            //创建一个连接对象
            MqttConnectOptions options = new MqttConnectOptions();
            // mqtt receive offline message若设为false，MQTT服务器将持久化客户端会话的主体订阅和ACK位置，
            // 默认为true。
            options.setCleanSession(false);
//            options.setSSLProperties();
            //设置超时时间
            options.setConnectionTimeout(10 * 1000);
            //设置会话心跳时间 单位为秒
            // 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线，但这个方法并没有重连的机制
            options.setKeepAliveInterval(20);
//设置最终端口的通知消息 :设置“遗嘱”消息的话题，若客户端与服务器之间的连接意外中断，服务器将发布客户端的“遗嘱”消息。
            //设置“遗嘱”消息的内容，默认是长度为零的消息。
            //设置“遗嘱”消息的QoS，默认为QoS.ATMOSTONCE。
            //若想要在发布“遗嘱”消息时拥有retain选项，则为true
//            options.setWill("will", );
//            options.setWill("LastWillTopic", "the client will stop !".getBytes(), 0, false);
            options.setUserName(sp.getString(MqttConstant.USERID, ""));
            options.setPassword(sp.getString(Constant.TOKEN, "").toCharArray());
//            mqttClient.log.isLoggable(Log.DEBUG);
            //创建客户端MQTT回调类
            if (callBack == null)
                callBack = new MqttMessageCallBack(context);
            //设置MQTT回调
            mqttClient.setCallback(callBack);
            mqttClient.connect(options);
//            LogUtil.d(TAG, "是否连接上了 : " + mqttClient.isConnected());

            if (!mqttClient.isConnected())
                return;

            if (MqttConstant.TOPICS != null && MqttConstant.TOPICS.length > 0)
                mqttClient.subscribe(MqttConstant.TOPICS);

        } catch (MqttException e) {
            e.printStackTrace();
        }

    }

    /**
     * 发送聊天内容
     *
     * @param mb    发送的内容
     * @param topic 聊天的主题topic
     */
    public void setMessage(String topic, MessageBean mb) throws Exception {

        if (mqttClient == null || !mqttClient.isConnected()) {//如果没有连接聊天服务器,提示聊天服务器未连接
            throw new Exception(MqttConstant.MQTTNOTCONNECT);
        }

        MqttTopic sendTopic = mqttClient.getTopic(topic);

        Log.e(TAG, "发送的内容：" + mb.content);

        Log.d(TAG, "  发送聊天消息 " + mb.content + ", 线程:" + Thread.currentThread().getName());
        sendTopic.publish(getSendMsg(mb).getBytes(), MqttConstant.MQTT_QOS_ONCE, false);
//            Toast.makeText(context, "发送!", Toast.LENGTH_SHORT).show();
        if (MqttConstant.OFF_GROUP.equals(mb.operationStyle))
            return; //退出群后发送的消息就不要再存储到数据库了

        //保存聊天记录到数据库, 消息状态(为发送中)
        save2DataBase(mb, MqttConstant.MESSAGE_SENDING);

        mb.operationStyle = MqttConstant.RECEIVE_MESSAGE;
        EventBus.getDefault().post(mb); //通知fragment页面有新消息

    }

    /**
     * 把发送的时候 无需的字段 置空
     *
     * @param mb
     */
    private String getSendMsg(MessageBean mb) throws Exception {

        JSONObject j = new JSONObject();

        j.put("sendPic", mb.sendPic);
        j.put("sendName", mb.sendName);
        j.put("sendId", mb.sendId);
        j.put("messageType", mb.messageType);

        if (mb.voiceLength < 1)
            mb.voiceLength = 1;
        else if (mb.voiceLength > 60)
            mb.voiceLength = 60;

        j.put("voiceLength", mb.voiceLength);
        j.put("sendDate", mb.sendDate + "");

        switch (mb.messageType) {

            case MqttConstant.MQTTMESSAGETEXT://文字
                j.put("content", mb.content);
                break;

            case MqttConstant.MQTTMESSAGEPHOTO://图片
                j.put("content", mb.qiniuPath);
                break;

            case MqttConstant.MQTTMESSAGEVOICE://语音
                //把文件路径转成base64的字符串
                j.put("content", File2Code.encodeBase64File(mb.content));
                break;

            case MqttConstant.MQTTMESSAGENOTICE:
                j.put("receivePic", mb.receivePic);
                j.put("receiveName", mb.receiveName);
                j.put("content", mb.content);
                break;

        }

        return j.toJSONString();

    }

    /**
     * 保存数据到数据库
     *
     * @param status 消息状态
     */
    public void save2DataBase(MessageBean mb, int status) {

        Log.d(TAG, "保存聊天消息到数据库: " + mb.content);
        //保存到history表,, 最后一个参数1表示发送中...
        DatabaseManager.getInstance().insertHisData(context, new Object[]{mb.sendId, mb.sendName, mb.sendPic, mb.sendDate,
                0, mb.content, mb.channelId, mb.messageType, mb.receiveId, mb.receiveName, mb.receivePic,
                mb.voiceLength, mb.chatType, mb.sendDate, sp.getString(MqttConstant.USERID, ""), MqttConstant.LISTENERED, status});

        //保存到topic表
        DatabaseManager.getInstance().updateTopic(context, new String[]{mb.receiveName, mb.sendId, mb.sendName,
                mb.sendPic, mb.sendDate + "", mb.receiveId, mb.content, mb.messageType,
                mb.voiceLength + "", mb.chatType + "", mb.sendDate + "", mb.receivePic,
                mb.receiveName, MqttConstant.LISTENERED + "", "0", mb.channelId, sp.getString(MqttConstant.USERID, "")});

    }

    /**
     * 订阅主题
     */
    void subTopicSingle(String topic) {

        if (mqttClient != null && mqttClient.isConnected()) {
            try {

                mqttClient.timeToWait = 500;//要把 timeToWait 的值改变 不知道为什么....
                mqttClient.subscribe(topic, MqttConstant.MQTT_QOS_SUB);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 取消订阅主题
     */
    public void unSubTopic(String topic) {

        if (mqttClient != null && mqttClient.isConnected()) {
            try {

                mqttClient.timeToWait = 500;//要把 timeToWait 的值改变 不知道为什么....
                mqttClient.unsubscribe(topic);

//                LogUtil.e(TAG, " 取消订阅的topic:" + topic);
//                removeSpTopic(topic);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

//    /**
//     * 清除sp中的topic
//     */
//    private void removeSpTopic(String mTopic) {
//
//        //sp中该topic清掉
//        if (MqttConstant.topicMap == null)
//            MqttConstant.topicMap = (Map<String, TopicBean>) JSON.parse(sp.getString(MqttConstant.TOPIC_MAP, ""));
//
//        if (MqttConstant.topicMap != null) {
//            MqttConstant.topicMap.remove(mTopic);
//        }
//
//        Map<String, TopicBean> spMap = (Map<String, TopicBean>) JSON.parse(sp.getString(MqttConstant.TOPIC_MAP, ""));
//        if (spMap != null) {
//            spMap.remove(mTopic);
//            sp.edit().putString(MqttConstant.TOPIC_MAP, JSON.toJSONString(spMap, true)).apply();
//        }
//
//    }

}